#include <windows.h>
#include <Commdlg.h>
#include "FileDialogs.h"
#include <malloc.h>

TCHAR* OpenFileDlg(const TCHAR* extsCatagory,
				   const TCHAR** exts,
				   HWND wnd)
{
	TCHAR* filePath;
	OPENFILENAME  ofn;
	BOOL          success;
	unsigned int  filterLen, extsCatLen, offset, len;
	const TCHAR** pp;
	const TCHAR*  p;
	TCHAR*        filter, * filterp;

	filePath  = (TCHAR*)malloc(MAX_PATH * sizeof(TCHAR));
	*filePath = (TCHAR)'\0';

	// Struct size
	ofn.lStructSize = sizeof(OPENFILENAME);
	
	// Handle to the window that owns the dialog box. This member can
	// be any valid window handle, or it can be NULL if the dialog box
	// has no owner.
	ofn.hwndOwner = wnd;
	
	// If the OFN_ENABLETEMPLATEHANDLE flag is set in the Flags member,
	// hInstance is a handle to a memory object containing a dialog box
	// template.
	ofn.hInstance = NULL;

	// Pointer to a buffer containing pairs of null-terminated filter
	// strings. The last string in the buffer must be terminated by two 
	// NULL characters.
	// The first string in each pair is a display string that describes 
	// the filter (for example, "Text Files"), and the second string 
	// specifies the filter pattern (for example, "*.TXT"). To specify 
	// multiple filter patterns for a single display string, use a 
	// semicolon to separate the patterns (for example, "*.TXT;*.DOC;).
	// A pattern string can be a combination of valid file name 
	// characters and the asterisk (*) wildcard character. Do not include 
	// spaces in the pattern string.
	//
	// The system does not change the order of the filters. It displays 
	// them in the File Types combo box in the order specified in 
	// lpstrFilter.
	//
	// If lpstrFilter is NULL, the dialog box does not display any filters.
	if (exts == NULL)
	{
		ofn.lpstrFilter = NULL;
	}
	else
	{
		// Get the length of what will be the filter string
		filterLen = 0;

		if (extsCatagory)
		{
#ifdef UNICODE
			extsCatLen = filterLen = wcslen(extsCatagory);
#else
			extsCatLen = filterLen = strlen(extsCatagory);
#endif
		}
		for (pp = exts, p = *pp; p != NULL; ++pp, p = *pp)
		{
#ifdef UNICODE
			filterLen += (wcslen(p) + 3);
#else
			filterLen += (strlen(p) + 3);
#endif
		}

		// Fill the filter string
		filter = malloc((filterLen + 3) * sizeof(TCHAR));

		if (extsCatagory)
		{
			memcpy(filter, extsCatagory, sizeof(TCHAR) * (extsCatLen + 1));
			offset = extsCatLen + 1;
		}
		else
		{
			offset = 0;
		}

		for (filterp = filter + offset, pp = exts, p = *pp; p != NULL; ++pp, p = *pp)
		{
			filterp[0] = (TCHAR)'*';
			filterp[1] = (TCHAR)'.';

			filterp += 2;
#ifdef UNICODE
			len = wcslen(p);
#else
			len = strlen(p);
#endif
			memcpy(filterp, p, sizeof(TCHAR) * len);

			filterp += len;

			*filterp = (TCHAR)';';

			++filterp;
		}
		*(filterp)     = '\0';
		*(filterp + 1) = '\0';

		ofn.lpstrFilter = filter;
	}

	// If this member is NULL, the dialog box does not preserve user-
	// defined filter patterns.
	ofn.lpstrCustomFilter = NULL;

	// Pointer to a buffer that contains a file name used to initialize 
	// the File Name edit control. This is also the buffer that recieves
	// the user's file path choice. The first character of this buffer 
	// must be NULL if initialization is not necessary.
	ofn.lpstrFile = filePath;

	// Pointer to a buffer that receives the file name and extension
	// (without path information) of the selected file. This member can 
	// be NULL.
	ofn.lpstrFileTitle = NULL;

	// The initial directory that the dialog is looking at
	ofn.lpstrInitialDir = NULL;
	
	// Pointer to a string to be placed in the title bar of the dialog box.
	// If this member is NULL, the system uses the default title (that is, 
	// Save As or Open).
	ofn.lpstrTitle = NULL;

	// Pointer to a buffer that contains the default extension.
	ofn.lpstrDefExt    = NULL;
	ofn.lCustData      = 0;
	ofn.lpfnHook       = NULL;
	ofn.lpTemplateName = NULL;
	ofn.Flags          = OFN_HIDEREADONLY;
	ofn.FlagsEx        = 0;
	ofn.nMaxFileTitle  = MAX_PATH;
	ofn.nMaxFile       = MAX_PATH;
	ofn.nMaxCustFilter = 0;
	ofn.nFilterIndex   = 0;
	ofn.nFileOffset    = 0;
	ofn.nFileExtension = 0;

	success = GetOpenFileName(&ofn);

	free(filter);

	if (success)
		return filePath;
	else
		return NULL;
}

TCHAR* SaveFileDlg(const TCHAR* extsCatagory,
				   const TCHAR** exts,
				   HWND wnd)
{
	TCHAR* filePath;
	OPENFILENAME  ofn;
	BOOL          success;
	unsigned int  filterLen, extsCatLen, offset, len;
	const TCHAR** pp;
	const TCHAR*  p;
	TCHAR*        filter, * filterp;

	filePath  = (TCHAR*)malloc(MAX_PATH * sizeof(TCHAR));
	*filePath = (TCHAR)'\0';

	// Struct size
	ofn.lStructSize = sizeof(OPENFILENAME);
	
	// Handle to the window that owns the dialog box. This member can
	// be any valid window handle, or it can be NULL if the dialog box
	// has no owner.
	ofn.hwndOwner = wnd;
	
	// If the OFN_ENABLETEMPLATEHANDLE flag is set in the Flags member,
	// hInstance is a handle to a memory object containing a dialog box
	// template.
	ofn.hInstance = NULL;

	// Pointer to a buffer containing pairs of null-terminated filter
	// strings. The last string in the buffer must be terminated by two 
	// NULL characters.
	// The first string in each pair is a display string that describes 
	// the filter (for example, "Text Files"), and the second string 
	// specifies the filter pattern (for example, "*.TXT"). To specify 
	// multiple filter patterns for a single display string, use a 
	// semicolon to separate the patterns (for example, "*.TXT;*.DOC;).
	// A pattern string can be a combination of valid file name 
	// characters and the asterisk (*) wildcard character. Do not include 
	// spaces in the pattern string.
	//
	// The system does not change the order of the filters. It displays 
	// them in the File Types combo box in the order specified in 
	// lpstrFilter.
	//
	// If lpstrFilter is NULL, the dialog box does not display any filters.
	if (exts == NULL)
	{
		ofn.lpstrFilter = NULL;
	}
	else
	{
		// Get the length of what will be the filter string
		filterLen = 0;

		if (extsCatagory)
		{
#ifdef UNICODE
			extsCatLen = filterLen = wcslen(extsCatagory);
#else
			extsCatLen = filterLen = strlen(extsCatagory);
#endif
		}
		for (pp = exts, p = *pp; p != NULL; ++pp, p = *pp)
		{
#ifdef UNICODE
			filterLen += (wcslen(p) + 3);
#else
			filterLen += (strlen(p) + 3);
#endif
		}

		// Fill the filter string
		filter = malloc((filterLen + 3) * sizeof(TCHAR));

		if (extsCatagory)
		{
			memcpy(filter, extsCatagory, sizeof(TCHAR) * (extsCatLen + 1));
			offset = extsCatLen + 1;
		}
		else
		{
			offset = 0;
		}

		for (filterp = filter + offset, pp = exts, p = *pp; p != NULL; ++pp, p = *pp)
		{
			filterp[0] = (TCHAR)'*';
			filterp[1] = (TCHAR)'.';

			filterp += 2;
#ifdef UNICODE
			len = wcslen(p);
#else
			len = strlen(p);
#endif
			memcpy(filterp, p, sizeof(TCHAR) * len);

			filterp += len;

			*filterp = (TCHAR)';';

			++filterp;
		}
		*(filterp)     = '\0';
		*(filterp + 1) = '\0';

		ofn.lpstrFilter = filter;
	}

	// If this member is NULL, the dialog box does not preserve user-
	// defined filter patterns.
	ofn.lpstrCustomFilter = NULL;

	// Pointer to a buffer that contains a file name used to initialize 
	// the File Name edit control. This is also the buffer that recieves
	// the user's file path choice. The first character of this buffer 
	// must be NULL if initialization is not necessary.
	ofn.lpstrFile = filePath;

	// Pointer to a buffer that receives the file name and extension
	// (without path information) of the selected file. This member can 
	// be NULL.
	ofn.lpstrFileTitle = NULL;

	// The initial directory that the dialog is looking at
	ofn.lpstrInitialDir = NULL;
	
	// Pointer to a string to be placed in the title bar of the dialog box.
	// If this member is NULL, the system uses the default title (that is, 
	// Save As or Open).
	ofn.lpstrTitle = NULL;

	// Pointer to a buffer that contains the default extension.
	ofn.lpstrDefExt    = NULL;
	ofn.lCustData      = 0;
	ofn.lpfnHook       = NULL;
	ofn.lpTemplateName = NULL;
	ofn.Flags          = OFN_HIDEREADONLY;
	ofn.FlagsEx        = 0;
	ofn.nMaxFileTitle  = MAX_PATH;
	ofn.nMaxFile       = MAX_PATH;
	ofn.nMaxCustFilter = 0;
	ofn.nFilterIndex   = 0;
	ofn.nFileOffset    = 0;
	ofn.nFileExtension = 0;

	success = GetSaveFileName(&ofn);

	free(filter);

	if (success)
		return filePath;
	else
		return NULL;
}